package com.vecspace.data.model;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.vecspace.dicttable.DictAll;
import com.vecspace.exception.HException;
import com.vecspace.utils.Convert;
import com.vecspace.utils.StringHelper;

/**以Map的方式存储数据库表中的一行记录
 *  
 */
public class DataEntity implements Map<String,Object>{// 测试代码：DbEntityTest
	/**表名（始终为大写字母）*/
	private String tableName;
	/**表中id字段的字段名*/
	private String idColumn;
	/**记录数据表中的一条记录。
	 * key值不直接存储字段名，而是字段名的小驼峰写法比如 "ID"-->"id", "user_name"-->"userName"
	 */
	Map<String,Object> row = new HashMap<>();
	public DataEntity(){
		
	}
	
	public DataEntity(String tableName){
		setTableName(tableName);
	}
	
	/**判断是否包含指定的属性名*/
	public boolean containsPropName(String propName) {
		return row.containsKey(propName);
	}
	/**根据属性名（属性名称，字段名的小驼峰拼写法）或者字段名返回字符串
	 * 如果不存在，则然后null
	 * @param columnName
	 * @return 
	 */
	
	public String getString(String propName){
		Object obj = this.get(propName);
		if(obj != null) {
			return obj.toString();
		}
		else {
			return null;
		}
	}

	/**根据属性名（属性名称，字段名的小驼峰拼写法）或者字段名返回Date，或者new Date(0)
	 * 如果不存在，则返回null
	 * @param columnName
	 * @return 
	 */
	public Date getDate(String propName){
		Object obj = this.get(propName);
		if(obj != null) {
			return Convert.toDate(obj, new Date(0));
		}
		else {
			return null;
		}
	}
	
	/**根据属性名（属性名称，字段名的小驼峰拼写法）或者字段名返回数字，或者defaultValue
	 * 
	 * @param columnName
	 * @return 
	 */
	public int getInt(String propName, int defaultValue){
		Object obj = this.get(propName);
		if(obj != null) {
			return Convert.toInt(obj, defaultValue);
		}
		else {
			return defaultValue;
		}
	}
	
	/**根据属性名（属性名称，字段名的小驼峰拼写法）或者字段名返回数字，或者defaultValue
	 * 
	 * @param columnName
	 * @return 
	 */
	public long getLong(String propName, long defaultValue){
		Object obj = this.get(propName);
		if(obj != null) {
			return Convert.toLong(obj, defaultValue);
		}
		else {
			return defaultValue;
		}
	}
	
	/**根据属性名（属性名称，字段名的小驼峰拼写法）或者字段名返回数字，或者defaultValue
	 * 
	 * @param columnName
	 * @return 
	 */
	public double getDouble(String propName, double defaultValue){
		Object obj = this.get(propName);
		if(obj != null) {
			return Convert.toDouble(obj, defaultValue);
		}
		else {
			return defaultValue;
		}
	} 
	@Override
	public int size() {
		return row.size();
	}
	@Override
	public boolean isEmpty() {
		return row.isEmpty();
	}
	@Override
	public boolean containsKey(Object key) {
		return row.containsKey(key);
	}
	@Override
	public boolean containsValue(Object value) {
		return row.containsValue(value);
	}
	/**根据columnName和propName中的任一项获取value*/
	@Override
	public Object get(Object key) {
		Object obj = row.get(key);
		if(obj == null){
			if(!row.containsKey(key)){
				String propName = StringHelper.lowerCamelCase(key.toString());
				obj = row.get(propName);
			}
		}
		return obj;
	}
	@Override
	@Deprecated
	public Object put(String key, Object value) {
//		String columnName = StringHelper.lowerCamelCase(key);
//		return row.put(columnName, value);
		try {
			throw new Exception("此方法不可使用，请用setByColumnName或者setByPropName代替");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
	
	/**根据字段名更新值，如果字段名（字段名代表的propName）不存在，则抛出异常
	 * @param columnName
	 * @param value
	 * @return
	 */
	public Object updateValueByColumnName(String columnName, Object value) throws HException {
		String propName = StringHelper.lowerCamelCase(columnName);
		if(!row.containsKey(propName)) {
			throw new HException("字段<"+columnName+">不存在");
		}
		return row.put(propName, value);
	}
	
	/**根据属性名更新值，如果propName不存在，则抛出异常
	 * @param propName
	 * @param value
	 * @return
	 */
	public Object updateValueByPropName(String propName, Object value) throws HException {
		if(!row.containsKey(propName)) {
			throw new HException("属性<"+propName+">不存在");
		}
		return row.put(propName, value);
	}
	
	/**添加（或者修改）一个字段值，不判断columnName代表的propName是否已经存在
	 * @param columnName
	 * @param value
	 * @return 
	 */
	public Object addValueByColumnName(String columnName, Object value) {
		String propName = StringHelper.lowerCamelCase(columnName);
		return row.put(propName, value);
	}

	/**添加（或者修改）一个属性值，不判断propName是否已经存在
	 * @param propName
	 * @param value
	 * @return 
	 */
	public Object addValueByPropName(String propName, Object value) {
		return row.put(propName, value);
	}
	
	@Override
	public Object remove(Object key) {
		return row.remove(key);
	}
	@Deprecated
	@Override
	public void putAll(Map<? extends String, ? extends Object> m) {
		try {
			throw new Exception("此方法不可使用，请用putAllByColumnName或者putAllByPropName代替");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void addAllByColumnName(Map<? extends String, ? extends Object> m){
		if(m == null) {
			return;
		}
		for(Entry<? extends String, ? extends Object> entry : m.entrySet()){
			this.addValueByColumnName(entry.getKey(), entry.getValue());
		}
	}
	

	public void addAllByPropName(Map<? extends String, ? extends Object> m){
		if(m == null) {
			return;
		}
		for(Entry<? extends String, ? extends Object> entry : m.entrySet()){
			this.addValueByPropName(entry.getKey(), entry.getValue());
		}
	}
	@Override
	public void clear() {
		row.clear();
	}
	@Override
	public Set<String> keySet() {
		return row.keySet();
	}
	@Override
	public Collection<Object> values() {
		return row.values();
	}
	@Override
	public Set<java.util.Map.Entry<String, Object>> entrySet() {
		return row.entrySet();
	}
	
	/**返回字段名和字段值的集合*/
	public Set<java.util.Map.Entry<String, Object>> columnValueSet() {
		return row.entrySet();
	}

	public String getTableName() {
		return tableName;
	}

	/**设置表名，并且始终转为大写字母*/
	public void setTableName(String tableName) {
		if(tableName == null) {
			return;
		}
		this.tableName = tableName.toUpperCase();
	}
	
	public String convert2ColumnName(String propName){
		return StringHelper.toUnderscoreName(propName);
	}

	public String getIdColumn() {
		return idColumn;
	}

	public void setIdColumn(String idColumn) {
		this.idColumn = idColumn;
	}
	/**设置属性（字段）的代码类型。同时添加一个字段，将代码对象的名称填入改字段
	 * 
	 * @param propName 属性名（不能是字段名）
	 * @param codeType 代码类型。对应T_DICT_ALL.CODE_TYPE字段的值
	 */
	public void setCodeType(String propName, String codeType){
		if(codeType == null || codeType.length()==0) {
			return;
		}
		String namePropName = propName+"Caption";//定义名称字段的属性名
		String code = this.getString(propName);
		String name = DictAll.getCachedItemName(codeType, code);//获取
		this.addValueByPropName(namePropName, name);//将代码对应的名称添加到几何中
	}
	
	/**对所有的记录，
	 * 设置属性（字段）的代码类型。同时添加一个字段，将代码对象的名称填入改字段
	 * 
	 * @param items 
	 * @param propName 属性名（不能是字段名）
	 * @param codeType 代码类型。对应T_DICT_ALL.CODE_TYPE字段的值
	 */
	public static void setCodeType(List<DataEntity> items,String propName, String codeType){
		if(items == null || items.size() == 0) {
			return;
		}
		if(codeType == null || codeType.length()==0) {
			return;
		}
		for(DataEntity item : items){
			item.setCodeType(propName, codeType);
		}
	}
}
